﻿using System;
using System.Linq.Expressions;
using System.Net;
using System.Reflection;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.ComponentModel;
using System.Windows.Threading;

namespace ArchitectingInnovation.PRISMvvM.Core
{
    public class ViewModelBase<T> : INotifyPropertyChanged
    {
        public ViewModelBase(T view)
        {
            this.View = view;
            
        }

        public T View { get; protected set; }

        public bool IsBusy
        {
            get { return _isBusy; }
            set
            {
                _isBusy = value;
                this.OnPropertyChanged(x => this.IsBusy);
            }
        }

        public virtual void InvalidateView()
        {
            this.OnPropertyChanged(String.Empty);
        }

        private bool _isBusy;

        protected void OnPropertyChanged<TProperty>(Expression<Func<object, TProperty>> propertyLambda)
        {
            var propInfo = GetPropertyInfo(propertyLambda);
            this.OnPropertyChanged(propInfo.Name);

        }

        public PropertyInfo GetPropertyInfo<TProperty>(Expression<Func<object, TProperty>> propertyLambda)
        {
            Type type = this.GetType();

            var member = propertyLambda.Body as MemberExpression;
            if (member == null)
                throw new ArgumentException(string.Format(
                    "Expression '{0}' refers to a method, not a property.",
                    propertyLambda.ToString()));

            var propInfo = member.Member as PropertyInfo;
            if (propInfo == null)
                throw new ArgumentException(string.Format(
                    "Expression '{0}' refers to a field, not a property.",
                    propertyLambda.ToString()));

            if (type != propInfo.ReflectedType &&
                !type.IsSubclassOf(propInfo.ReflectedType))
                throw new ArgumentException(string.Format(
                    "Expresion '{0}' refers to a property that is not from type {1}.",
                    propertyLambda.ToString(),
                    type));

            return propInfo;
        }
       

        protected virtual void OnPropertyChanged(string propertyName)
        {
            if(PropertyChanged != null)
            {
                Application.Current.RootVisual.Dispatcher.BeginInvoke(
                    () => PropertyChanged(this, new PropertyChangedEventArgs(propertyName)));
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;
    }
}
